package client.inventory

import constants.ItemConstants
import server.MapleItemInformationProvider
import tools.Randomizer
import java.util.*
import kotlin.collections.HashMap

data class NirvanaFlame(var nstr: Short = 0, var ndex: Short = 0, var nint: Short = 0, var nluk: Short = 0, var nhp: Short = 0, var nmp: Short = 0, var nwatk: Short = 0,
                        var nmatk: Short = 0, var nwdef: Short = 0, var nmdef: Short = 0, var nacc: Short = 0, var navoid: Short = 0, var nhands: Short = 0,
                        var nspeed: Short = 0, var njump: Short = 0, var nbossDamage: Short = 0, var nignorePDR: Short = 0, var ntotalDamage: Short = 0,
                        var nallStat: Short = 0) {

    constructor(n: NirvanaFlame) : this() {
        nstr = n.nstr
        ndex = n.ndex
        nint = n.nint
        nluk = n.nluk
        nhp = n.nhp
        nmp = n.nmp
        nwatk = n.nwatk
        nmatk = n.nmatk
        nwdef = n.nwdef
        nmdef = nmdef
        nacc = n.nacc
        navoid = n.navoid
        nhands = n.nhands
        nspeed = n.nspeed
        njump = n.njump
        nbossDamage = n.nbossDamage
        nignorePDR = n.nignorePDR
        ntotalDamage = n.ntotalDamage
        nallStat = n.nallStat
    }

    fun reset() {
        nstr = 0
        ndex = 0
        nint = 0
        nluk = 0
        nhp = 0
        nmp = 0
        nwatk = 0
        nmatk = 0
        nwdef = 0
        nmdef = 0
        nacc = 0
        navoid = 0
        nhands = 0
        nspeed = 0
        njump = 0
        nbossDamage = 0
        nignorePDR = 0
        ntotalDamage = 0
        nallStat = 0
    }

    companion object {
        fun randomState(equip: Equip, scrollid: Int) {
            val allstates = HashMap<EquipExFlag, Int>()
            var value = ItemConstants.UpgradeItemEx.getValue(scrollid)
            val min: Int
            val max: Int
            when {
                equip.reqLevel < 30 -> {
                    min = 1
                    max = 2
                }
                equip.reqLevel < 90 -> {
                    min = 1
                    max = 3
                }
                equip.reqLevel < 110 -> {
                    min = 2
                    max = 3
                }
                equip.reqLevel < 150 -> {
                    min = 2
                    max = 4
                }
                else -> {
                    min = 3
                    max = 4
                }
            }
            val nextInt = Randomizer.nextInt(100)
            value = when {
                nextInt < 5 -> Randomizer.rand(3, value)
                nextInt < 10 -> Randomizer.rand(2, value - 1)
                nextInt < 20 -> Randomizer.rand(2, value - 2)
                nextInt < 30 -> Randomizer.rand(1, value - 2)
                else -> {
                    if (nextInt >= 40) {
                    }
                    Randomizer.rand(1, value - 3)
                }
            }
            val total = Randomizer.rand(min, max)
            allstates.put(EquipExFlag.FLAGEX_DEX, 70)
            allstates.put(EquipExFlag.FLAGEX_DEX, 70)
            allstates.put(EquipExFlag.FLAGEX_INT, 70)
            allstates.put(EquipExFlag.FLAGEX_LUK, 70)
            allstates.put(EquipExFlag.FLAGEX_STR_DEX, 70)
            allstates.put(EquipExFlag.FLAGEX_STR_INT, 70)
            allstates.put(EquipExFlag.FLAGEX_STR_LUK, 70)
            allstates.put(EquipExFlag.FLAGEX_DEX_INT, 70)
            allstates.put(EquipExFlag.FLAGEX_DEX_LUK, 70)
            allstates.put(EquipExFlag.FLAGEX_INT_LUK, 70)
            allstates.put(EquipExFlag.FLAGEX_MAXHP, 65)
            allstates.put(EquipExFlag.FLAGEX_MAXMP, 65)

            if (ItemConstants.isWeapon(equip.itemId)) {
                if (ItemConstants.isMagicWeapon(equip.itemId)) {
                    allstates.put(EquipExFlag.FLAGEX_MAD, 70)
                } else {
                    allstates.put(EquipExFlag.FLAGEX_PAD, 70)
                }
            } else {
                allstates.put(EquipExFlag.FLAGEX_PAD, 70)
                allstates.put(EquipExFlag.FLAGEX_MAD, 70)
            }
            allstates.put(EquipExFlag.FLAGEX_PDD, 70)
            allstates.put(EquipExFlag.FLAGEX_SPEED, 50)
            allstates.put(EquipExFlag.FLAGEX_JUMP, 50)

            if (equip.reqLevel >= 130) {
                allstates.put(EquipExFlag.FLAGEX_STATR, 10)
                if (ItemConstants.isWeapon(equip.itemId)) {
                    allstates.put(EquipExFlag.FLAGEX_BDR, 10)
                    allstates.put(EquipExFlag.FLAGEX_DAMR, 10)
                    allstates.put(EquipExFlag.FLAGEX_GNOREPDR, 10)
                }
            }

            val ret = HashMap<EquipExFlag, Int>()
            val allEquipFlag = EquipExFlag.values()
            var exGradeOption = 0L
            while (ret.size < total) {
                val list = allEquipFlag.toMutableList()
                Collections.shuffle(list)
                val flag = list[Randomizer.nextInt(list.size)]
                if (allstates.containsKey(flag) && !ret.containsKey(flag) && Randomizer.isSuccess(allstates[flag]!!)) {
                    ret.put(flag, Math.max(1, value))
                }
            }
            ret.forEach { t, u -> exGradeOption = exGradeOption * 1000 + (t.mask + u) }
            applyState(equip, exGradeOption)
        }

        fun applyState(equip: Equip, exGradeOption: Long) {
            val reqLevel = MapleItemInformationProvider.getInstance().getReqLevel(equip.itemId)
            val isWeapon = ItemConstants.isWeapon(equip.itemId)
            val randFlagExs = java.util.HashMap<Any, Int>()
            val defEquip: Equip = MapleItemInformationProvider.getInstance().getEquipById(equip.itemId) as Equip
            val rate = reqLevel / 40 + 1 shl 1
            var localExGradeOption = exGradeOption
            var n3 = exGradeOption % 1000L
            while (n3 > 0L) {
                localExGradeOption /= 1000L
                val n4 = (n3 / 10L * 10L).toInt()
                val n5 = n3.toInt() % 10
                val exFlag = EquipExFlag.getEnumByValue(n4)
                if (exFlag != null) {
                    randFlagExs.put(exFlag, n5)
                }
                n3 = localExGradeOption % 1000L
            }
            val nf = equip.nirvanaFlame
            nf.reset()
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_STR)) {
                nf.nstr = (rate * randFlagExs[EquipExFlag.FLAGEX_STR]!!).toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_DEX)) {
                nf.ndex = (rate * randFlagExs[EquipExFlag.FLAGEX_DEX]!!).toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_INT)) {
                nf.nint = (rate * randFlagExs[EquipExFlag.FLAGEX_INT]!!).toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_LUK)) {
                nf.nluk = (rate * randFlagExs[EquipExFlag.FLAGEX_LUK]!!).toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_STR_DEX)) {
                nf.nstr = (rate * randFlagExs[EquipExFlag.FLAGEX_STR_DEX]!! / 2).toShort()
                nf.ndex = (rate * randFlagExs[EquipExFlag.FLAGEX_STR_DEX]!! / 2).toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_STR_INT)) {
                nf.nstr = (rate * randFlagExs[EquipExFlag.FLAGEX_STR_INT]!! / 2).toShort()
                nf.nint = (rate * randFlagExs[EquipExFlag.FLAGEX_STR_INT]!! / 2).toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_STR_LUK)) {
                nf.nstr = (rate * randFlagExs[EquipExFlag.FLAGEX_STR_LUK]!! / 2).toShort()
                nf.nluk = (rate * randFlagExs[EquipExFlag.FLAGEX_STR_LUK]!! / 2).toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_DEX_INT)) {
                nf.ndex = (rate * randFlagExs[EquipExFlag.FLAGEX_DEX_INT]!! / 2).toShort()
                nf.nint = (rate * randFlagExs[EquipExFlag.FLAGEX_DEX_INT]!! / 2).toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_DEX_LUK)) {
                nf.ndex = (rate * randFlagExs[EquipExFlag.FLAGEX_DEX_LUK]!! / 2).toShort()
                nf.nluk = (rate * randFlagExs[EquipExFlag.FLAGEX_DEX_LUK]!! / 2).toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_INT_LUK)) {
                nf.nint = (rate * randFlagExs[EquipExFlag.FLAGEX_INT_LUK]!! / 2).toShort()
                nf.nluk = (rate * randFlagExs[EquipExFlag.FLAGEX_INT_LUK]!! / 2).toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_MAXHP)) {
                nf.nhp = (Math.max(1, reqLevel) * 3 * randFlagExs[EquipExFlag.FLAGEX_MAXHP] as Int).toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_MAXMP)) {
                nf.nmp = (Math.max(1, reqLevel) * 3 * randFlagExs[EquipExFlag.FLAGEX_MAXMP] as Int).toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_PAD)) {
                var shortValue = randFlagExs[EquipExFlag.FLAGEX_PAD]!!.toShort()
                if (isWeapon) {
                    val n6 = defEquip.watk
                    val intValue = randFlagExs[EquipExFlag.FLAGEX_PAD]!!
                    shortValue = Math.floor(0.04444444444 * intValue.toDouble() * reqLevel.toDouble() / 100.0 * n6 / (1.0 + Math.exp(Math.pow(0.04444444444, intValue.toDouble()) - (intValue / 2).toDouble() - 0.8))).toShort()
                }
                nf.nwatk = shortValue
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_MAD)) {
                var shortValue2 = randFlagExs[EquipExFlag.FLAGEX_MAD]!!.toShort()
                if (isWeapon) {
                    val n7 = defEquip.matk
                    val intValue2 = randFlagExs[EquipExFlag.FLAGEX_MAD]!!
                    shortValue2 = Math.round(0.04444444444 * intValue2.toDouble() * reqLevel.toDouble() / 100.0 * n7 / (1.0 + Math.exp(Math.pow(0.04444444444, intValue2.toDouble()) - (intValue2 / 2).toDouble() - 0.8))).toShort()
                }
                nf.nmatk = shortValue2
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_PDD)) {
                nf.nwdef = (randFlagExs[EquipExFlag.FLAGEX_PDD]!!.toShort() * (reqLevel / 20 + 1)).toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_SPEED)) {
                nf.nspeed = randFlagExs[EquipExFlag.FLAGEX_SPEED]!!.toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_JUMP)) {
                nf.njump = randFlagExs[EquipExFlag.FLAGEX_JUMP]!!.toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_BDR)) {
                nf.nbossDamage = ((randFlagExs[EquipExFlag.FLAGEX_BDR]!!) shl 1).toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_DAMR)) {
                nf.ntotalDamage = randFlagExs[EquipExFlag.FLAGEX_DAMR]!!.toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_STATR)) {
                nf.nallStat = randFlagExs[EquipExFlag.FLAGEX_STATR]!!.toShort()
            }
            if (randFlagExs.containsKey(EquipExFlag.FLAGEX_GNOREPDR)) {
                nf.nignorePDR = randFlagExs[EquipExFlag.FLAGEX_GNOREPDR]!!.toShort()
            }
            equip.fire = exGradeOption
        }
    }
}


enum class EquipExFlag(val mask: Int) {
    FLAGEX_STR(0),
    FLAGEX_DEX(10),
    FLAGEX_INT(20),
    FLAGEX_LUK(30),
    FLAGEX_STR_DEX(40),
    FLAGEX_STR_INT(50),
    FLAGEX_STR_LUK(60),
    FLAGEX_DEX_INT(70),
    FLAGEX_DEX_LUK(80),
    FLAGEX_INT_LUK(90),
    FLAGEX_MAXHP(100),
    FLAGEX_MAXMP(110),
    FLAGEX_REQLEVEL(120),
    FLAGEX_PDD(130),
    FLAGEX_AVOID(140),
    FLAGEX_EVA(150),
    FLAGEX_CRAFT(160),
    FLAGEX_PAD(170),
    FLAGEX_MAD(180),
    FLAGEX_SPEED(190),
    FLAGEX_JUMP(200),
    FLAGEX_BDR(210),
    FLAGEX_GNOREPDR(220),
    FLAGEX_DAMR(230),
    FLAGEX_STATR(240);

    companion object {
        private val flags = HashMap<Int, EquipExFlag>()

        init {
            values().forEach { flags.put(it.mask, it) }
        }

        fun getEnumByValue(mask: Int): EquipExFlag? {
            return flags[mask]
        }
    }
}